const { JJUser, JJCourseUserConfirm, Ctcdb, JJCourseAccount, JJUserAccountBill, JJCourseAccountBill, JJCourseSettleOrder,
  JJUserCourse, JJCourse, JJCourseCamp, JJCourseRefundApply, JJCourseCommission } = require('../../models/ctcdb');
const BaseResp = require('../../utils/baseResp');
const errorCode = require('../../utils/errorCode');
const courseCommonService = require('../course/commonService');
const moment = require('moment');
const SequenceUtil = require('../../utils/sequece');
const WxPay = require('../../utils/wxPay');
const refundService = require('../pay/refund');
const tools = require('../../utils/tools');

async function getList({ userId, offset, limit, querystatus, queryuid, type, isBuy }) {
  offset = offset && Number(offset) || 0;
  limit = limit && Number(limit) || 20;
  isBuy = isBuy && Number(isBuy) || 0;
  let confirmUid = userId; // 默认查自己的
  if (Number(queryuid)) {
    confirmUid = queryuid
  }
  // todo 考虑下已完结报不报退款
  const user  = await JJUser.findOne({
    where: {
      id: confirmUid
    },
    attributes: ['id', 'identity'],
    raw: true
  });
  const { identity } = user;
  if (identity === 0 || isBuy) {
    const where = {
      state: 1,
      jUserId: confirmUid,
      type: 1 // 查询课程的信息
    };
    querystatus = Number(querystatus);

    let sql = 'select' +
      ' jj_user_course.user_id as jUserId,' +
      ' jj_user_course.course_id as courseId,' +
      ' jj_user_course.jiao_user_id as lUserId,' +
      ' jj_user_course.state as state' +
      ' from' +
      ' jj_user_course' +
      ' left join jj_course on jj_course.id = jj_user_course.course_id' +
      ` where jj_course.status = 1 and jj_user_course.state = 1 and jj_user_course.user_id = ${confirmUid} and jj_user_course.type = 1`;
    let countSql = 'select' +
      ' count(*) as count' +
      ' from' +
      ' jj_user_course' +
      ' left join jj_course on jj_course.id = jj_user_course.course_id' +
      ` where jj_course.status = 1 and jj_user_course.state = 1 and jj_user_course.user_id = ${confirmUid} and jj_user_course.type = 1`;
    if (querystatus) {
      if (querystatus === 1) { // 查看未完结的，包括未预约和已预约的
        sql += ' and jj_user_course.status in (1,5)';
        countSql += ' and jj_user_course.status in (1,5)';
      } else {
        sql += ' and jj_user_course.status = 10';
        countSql += ' and jj_user_course.status = 10';
      }
    }
    if (Number(type)) {
      sql += ` and jj_course.type = ${type}`;
      countSql += ` and jj_course.type = ${type}`;
    }
    sql += ` order by jj_course.c_status asc ,jj_course.sign_end_time desc`;
    sql += ` limit ${offset},${limit}`;
    const [list, [{ count }]] = await Promise.all([
      Ctcdb.query(sql, { nest: true }),
      Ctcdb.query(countSql, { nest: true }),
    ]);
    if (count === 0) {
      return {
        list: [],
        count: 0
      }
    }
    const courseIds = [];
    list.forEach((item) => {
      courseIds.push(item.courseId);
    });
    const { imageMap, courseMap } = await courseCommonService.queryCourseOtherInfo(courseIds, { isImage: 1, isCourse: 1 });
    const array = [];
    list.forEach((item) => {
      if (courseMap[item.courseId]) {
        const Obj = Object.assign(courseMap[item.courseId], {
          images: imageMap[item.courseId]
        });
        array.push(Obj)
      }
    });
    return {
      list: array,
      count
    }
  } else {
    const where = {
      status: 1,
      JUserId: confirmUid
    };
    querystatus = Number(querystatus);
    if (querystatus) {
      where.cStatus = querystatus;
    }
    if (Number(type)) {
      where.type = type
    }
    const [list, count] = await Promise.all([
      JJCourse.findAll({
        where,
        offset,
        limit,
        sort: [['cStatus', 'asc'],['signEndTime', 'desc']],
        attributes: ['type', 'id', 'courseName', 'classNum', 'startTime', 'classTime',
          'totalMoney', 'peopleNum', 'label', 'storeName', 'description', 'JUserId', 'cStatus'],
        raw: true
      }),
      JJCourse.count({
        where
      })
    ]);
    if (count === 0) {
      return {
        list: [],
        count: 0
      }
    }
    const courseIds = [];
    list.forEach((item) => {
      courseIds.push(item.id);
    });
    const { imageMap } = await courseCommonService.queryCourseOtherInfo(courseIds, { isImage: 1});
    // const array = [];
    list.map((item) => {
      item.startTime = tools.formatHHMM(item.startTime);
      item.images = imageMap[item.id] || [];
      return item;
    });
    return {
      list,
      count
    }
  }
}

async function subscribe({ courseId, campId, userId }) {
  campId = Number(campId);
  // 课程不存在
  const course = await JJCourse.findOne({
    where: {
      id: courseId,
      status: 1
    },
    attributes: ['id', 'JUserId', 'cStatus', 'type', 'signEndTime'],
    raw: true
  });
  if (!course) {
    throw BaseResp.error(errorCode.COURSE.NOT_FOUND)
  }
  const { type, cStatus, JUserId: lUserId, signEndTime } = course;
  // 报名时间截止
  if (new Date(signEndTime) >= Date.now()) {
    throw BaseResp.error(errorCode.COURSE.TIME_END)
  }

  if (type !== 1 && !campId) { // 如果不是团课，要选择课时进行预约
    throw BaseResp.error(errorCode.COURSE.MUST_CHOOSE_CLASS)
  }
  // 查询用户是否购买过此课程
  const userCourse = await JJUserCourse.findOne({
    where: {
      jUserId: userId,
      courseId,
      type: 1,
      state: 1
    },
    attributes: ['id', 'status'],
    raw: true
  });
  if (!userCourse) {
    throw BaseResp.error(errorCode.COURSE.NOT_BUY)
  }
  // 类型（是团课的话） // todo 考虑下 是否有课时的情况下 这个主课程的值也发生变化
  if (type === 1) {
    // 销课了，不能预约
    if (cStatus !== 1) {
      throw BaseResp.error(errorCode.COURSE.CAN_NOT_SUB)
    }
    const { status: userCStatus, id: userCourseId } = userCourse;
    if (userCStatus !== 1) { // 用户已经预约过了
      throw BaseResp.error(errorCode.COURSE.HAS_SUB)
    }
    await JJUserCourse.update({
      status: 5 // 改成预约中
    }, {
      where: {
        id: userCourseId
      }
    })
  } else {
    const campInfo = await JJCourseCamp.findOne({
      where: {
        id: campId,
        courseId
      },
      attributes: ['cStatus', 'id'],
      raw: true
    });
    if (!campInfo) {
      throw BaseResp.error(errorCode.COURSE.NOT_CLASS)
    }
    const { cStatus: classCStatus } = campInfo;
    if (classCStatus !== 1) {
      throw BaseResp.error(errorCode.COURSE.CAN_NOT_SUB)
    }
    // 用户购买了，查询用户是否已经预约过
    const userCourserClass = await JJUserCourse.findOne({
      where: {
        jUserId: userId,
        courseId,
        campId,
        type: 2,
        state: 1
      },
      attributes: ['id', 'status'],
      raw: true
    });
    // 没有预约过
    // if (!userCourserClass || userCourserClass.status === 1) {
    //   await JJUserCourse
    // }
    // 这里主要是因为私教定制，可能还没有购买的时候存在的
    if (!userCourserClass) {
      await JJUserCourse.create({
        jUserId: userId,
        status: 5, // 直接预约
        courseId,
        lUserId, // 教练Id
        type: 2,
        campId
      });
    }
    if (userCourserClass.status === 1) {
      await JJUserCourse.update({
        status: 5  // 预约中
      }, {
        where: {
          id: userCourserClass.id
        }
      })
    }
    if (userCourserClass && userCourserClass.status !== 1) {
      throw BaseResp.error(errorCode.COURSE.HAS_SUB)
    }
  }
}

async function confirm({ userId, courseId }) {
  const [confirmInfo, count] = await Promise.all([
    JJCourseUserConfirm.findOne({
      where: {
        status: 0,
        jUserId: userId,
        courseId
      },
      attributes: ['status', 'id'],
      raw: true
    }),
    JJCourseUserConfirm.count({
      where: {
        status: 0,
        courseId
      }
    })
  ]);
  if (!confirmInfo) {
    throw BaseResp.error(errorCode.COURSE.COURSE_USER_CONFIRM)
  }
  let balance = 0;
  let lUserId = 0;
  let diffMoney = 0;
  let percent = 1; // 默认是1
  // 查询出金额
  if (count === 1) {
    const courseAccount = await JJCourseAccount.findOne({
      where: {
        courseId
      },
      attributes: ['status', 'balance', 'lUserId'],
      raw: true
    });
    if (!courseAccount) {
      throw BaseResp.error(errorCode.COURSE.COURSE_ACCOUNT_ERROR)
    }
    const courseInfo = await JJCourse.findOne({
      where: {
        id: courseId
      },
      attributes: ['id', 'type'],
      raw: true
    });
    const commissInfo = await JJCourseCommission.findOne({
      where: {
        type: courseInfo.type
      },
      attributes: ['percent'],
      raw: true
    });
    percent = commissInfo && commissInfo.percent/100;
    balance = courseAccount.balance;
    lUserId = courseAccount.lUserId;
    diffMoney = tools.dealNumberTwo(balance * percent)
  }
  const transaction = await Ctcdb.transaction();
  try {
    if (count === 1) {
      // 扣除课程账户余额
      let increseSql = `update jj_course_account set balance=balance - ${diffMoney} where jj_course_id = ${courseId}`;
      // 增加教练账户余额
      let addSql = `update jj_user_account set balance=balance+${diffMoney} where ref_jj_user_id=${lUserId}`;

      await Ctcdb.query(increseSql, { transaction });
      await JJCourseAccountBill.create({
        type: 2,
        courseId,
        amount: -diffMoney,
        remark: '销课'
      }, {
        transaction
      });

      await Ctcdb.query(addSql, { transaction });
      await JJUserAccountBill.create({
        userId: lUserId,
        type: 'COURSE_OFF',
        courseId,
        amount: diffMoney,
        remark: '销课'
      }, {
        transaction
      });
      // todo 修改课程账户状态
      // 修改账户的确认状态
      await JJCourse.update({
        isAgree: 1
      }, {
        where: {
          id:courseId
        },
        transaction
      });
      await JJCourseSettleOrder.update({
        status: 1,
        settleSum: diffMoney,
        settleTime: new Date()
      }, {
        where: {
          courseId
        },
        transaction
      })
    }
    await JJCourseUserConfirm.update({
      status: 1
    },{
      where: {
        id: confirmInfo.id
      },
      transaction
    })
    await transaction.commit();
  } catch (e) {
    if (transaction) {
      await transaction.rollback()
    }
    return Promise.reject(e)
  }
}

async function unSubscribe({ courseId, userId, remark }) {
  const [userCourse, course] = await Promise.all([
    JJUserCourse.findOne({
      where: {
        courseId,
        jUserId: userId,
        state: 1,
        type: 1
      },
      attributes: ['status', 'createTime', 'orderId'],
      raw: true
    }),
    await JJCourse.findOne({
      where: {
        id: courseId
      },
      attributes: ['status', 'cStatus', 'signEndTime', 'startTime', 'type', 'totalMoney', 'isSend', 'JUserId'],
      raw: true
    })
  ]);
  if (!course) {
    throw BaseResp.error(errorCode.COURSE.NOT_FOUND)
  }
  async function getWaitApply(queryUid) {
    let where = {
      courseId,
      applyUserId: queryUid,
      status: 0
    };
    return JJCourseRefundApply.findOne({
      where,
      attributes: ['id'],
      raw: true
    })
  }
  // 查询之前的用户是否申请过退款过
  const info = await getWaitApply(userId);
  // 说明还有待处理的申请取消
  if (info) {
    throw BaseResp.error(errorCode.APPLY.HAS_APPLY)
  }
  // fixme 这里考虑下 这里使用课程的金额，还是用实际购买时候的金额
  const { type, startTime, signEndTime, totalMoney, isSend, JUserId: lUserId, JUserId } = course;
  // 说明是学员发起的申请退款
  if (JUserId !== userId) {
    // 走学员退款
    if (!userCourse) {
      throw BaseResp.error(errorCode.COURSE.NOT_BUY_COURSE)
    }
    // 团课的退款模式
    if (type === 1) {
      // 未开始的课程
      if (new Date(startTime).getTime() > Date.now()) {
        const hours = moment(new Date(startTime)).diff(moment(), 'hours');
        // 费率
        const rate = await refundService.getRecentRefundRateByTime(hours);
        // const refundSum = totalMoney * (1 - rate) / 100; // 应该退款金额
        const { orderId } = userCourse;
        await refundService.refundNotStartBigCourse({ orderId, rate, type });
        return;
      }
      // 已经开始的图课不能退款
      throw BaseResp.error(errorCode.COURSE.CAN_NOT_REFUND)
    } else if (type === 2) {
      // 当为私教(这种都需要教练通过申请后，才能退款)
      await refundService.createRefundApply({ courseId, applyUserId: userId, handleUserId: lUserId, type: 1 });
    } else {
      // 训练营已报名截止时间为准
      if (new Date(signEndTime).getTime() > Date.now()) {
        const hours = moment(new Date(signEndTime)).diff(moment(), 'hours') - 1;
        // 费率
        const rate = await refundService.getRecentRefundRateByTime(hours);
        // const refundSum = totalMoney * (1 - rate) / 100; // 应该退款金额
        const { orderId } = userCourse;
        await refundService.refundNotStartCamp({ orderId, rate, type });
        return;
      }
      throw BaseResp.error(errorCode.COURSE.CAN_NOT_REFUND)
    }
  } else {
    let handle = 0;
    // 私人教这种 特别处理一下
    if (type === 2 && isSend === 1) {
       const userCourseInfo = await JJUserCourse.findOne({
          where: {
            type:1,
            state: 1,
            courseId
          },
          attributes: ['jUserId'],
          raw: true
        });
      if (userCourseInfo) {
        handle = userCourseInfo.jUserId
      }
    }
      // 发起申请退款
    await refundService.createRefundApply({ courseId, applyUserId: userId, handleUserId: handle, type: 2, remark });
  }
}

async function getUserConfirmList({ offset, limit, status, userId }) {
  const where = { status, jUserId: userId };

  const [list, count] = await Promise.all([
    JJCourseUserConfirm.findAll({
      where,
      attributes: ['jUserId', 'lUserId', 'courseId', 'status'],
      raw: true,
      offset,
      limit
    }),
    JJCourseUserConfirm.count({ where })
  ]);
  const courseIds = [];
  list.forEach((item) => {
    courseIds.push(item.courseId);
  });
  const { imageMap, courseMap } = await courseCommonService.queryCourseOtherInfo(courseIds, { isImage: 1, isCourse: 1 });
  const array = [];
  list.forEach((item) => {
    if (courseMap[item.courseId]) {
      const Obj = Object.assign(courseMap[item.courseId], {
        images: imageMap[item.courseId],
        status: item.status
      });
      array.push(Obj)
    }
  });
  return {
    list: array,
    count
  }
}

module.exports = {
  // 获取用户的课程列表
  getList,
  // 用户预约课程
  subscribe,
  // 用户确认销课
  confirm,
  // 取消预约
  unSubscribe,
  // 获取课程的用户确认列表
  getUserConfirmList
};
//
// console.log(moment(new Date('2019-10-02 22:25:01')).diff('2019-10-01 10:25:00', 'hours'));